package com.eduagent.xwqeduagent.tools;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.eduagent.xwqeduagent.constant.FileConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文件操作工具类（提供完整的文件读写功能）
 */
@Slf4j
@Component
public class FileOperationTool {

    private final String FILE_DIR = FileConstant.FILE_SAVE_DIR + "/file";
    private final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 限制文件大小为10MB
    private final List<String> ALLOWED_EXTENSIONS = Arrays.asList(
            "txt", "json", "xml", "csv", "md", "log", "properties", "yml", "yaml"
    );

    @Tool(description = "Read content from a file. Supports text files like txt, json, xml, csv, md, log, etc.")
    public String readFile(@ToolParam(description = "Name of the file to read (with extension)") String fileName) {
        log.info("Spring AI工具读取文件：{}", fileName);

        try {
            // 文件名安全检查
            if (!isValidFileName(fileName)) {
                return "错误：文件名包含非法字符或路径";
            }

            String filePath = FILE_DIR + "/" + fileName;
            File file = new File(filePath);

            // 检查文件是否存在
            if (!file.exists()) {
                return "错误：文件不存在 - " + fileName;
            }

            // 检查文件大小
            if (file.length() > MAX_FILE_SIZE) {
                return "错误：文件过大（超过10MB）- " + fileName;
            }

            // 检查文件扩展名
            if (!isAllowedFileType(fileName)) {
                return "错误：不支持的文件类型 - " + getFileExtension(fileName) +
                        "。支持的类型：" + String.join(", ", ALLOWED_EXTENSIONS);
            }

            String content = FileUtil.readUtf8String(filePath);

            // 如果内容太长，提供摘要信息
            if (content.length() > 5000) {
                String preview = content.substring(0, 2000) + "\n\n...[文件内容过长，已截取前2000字符]...\n\n" +
                        content.substring(Math.max(0, content.length() - 500));
                return String.format("文件读取成功：%s\n文件大小：%d 字符\n\n内容预览：\n%s",
                        fileName, content.length(), preview);
            }

            return String.format("文件读取成功：%s\n\n文件内容：\n%s", fileName, content);

        } catch (Exception e) {
            log.error("读取文件失败：{}", fileName, e);
            return "读取文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "Write content to a file. Will create directories if they don't exist.")
    public String writeFile(
            @ToolParam(description = "Name of the file to write (with extension)") String fileName,
            @ToolParam(description = "Content to write to the file") String content) {

        log.info("Spring AI工具写入文件：{}", fileName);

        try {
            // 文件名安全检查
            if (!isValidFileName(fileName)) {
                return "错误：文件名包含非法字符或路径";
            }

            // 内容长度检查
            if (StrUtil.isBlank(content)) {
                return "错误：写入内容不能为空";
            }

            if (content.length() > MAX_FILE_SIZE) {
                return "错误：写入内容过大（超过10MB）";
            }

            // 检查文件扩展名
            if (!isAllowedFileType(fileName)) {
                return "错误：不支持的文件类型 - " + getFileExtension(fileName) +
                        "。支持的类型：" + String.join(", ", ALLOWED_EXTENSIONS);
            }

            String filePath = FILE_DIR + "/" + fileName;

            // 创建目录
            FileUtil.mkdir(FILE_DIR);

            // 写入文件
            FileUtil.writeUtf8String(content, filePath);

            return String.format("文件写入成功：%s\n文件路径：%s\n内容长度：%d 字符\n写入时间：%s",
                    fileName, filePath, content.length(), new Date());

        } catch (Exception e) {
            log.error("写入文件失败：{}", fileName, e);
            return "写入文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "Append content to an existing file. Creates the file if it doesn't exist.")
    public String appendToFile(
            @ToolParam(description = "Name of the file to append to") String fileName,
            @ToolParam(description = "Content to append to the file") String content) {

        log.info("Spring AI工具追加文件内容：{}", fileName);

        try {
            if (!isValidFileName(fileName)) {
                return "错误：文件名包含非法字符或路径";
            }

            if (StrUtil.isBlank(content)) {
                return "错误：追加内容不能为空";
            }

            String filePath = FILE_DIR + "/" + fileName;

            // 创建目录
            FileUtil.mkdir(FILE_DIR);

            // 检查现有文件大小
            File file = new File(filePath);
            if (file.exists() && (file.length() + content.length()) > MAX_FILE_SIZE) {
                return "错误：追加后文件将超过大小限制（10MB）";
            }

            // 追加内容
            FileUtil.appendUtf8String(content, filePath);

            return String.format("内容追加成功：%s\n追加内容长度：%d 字符\n追加时间：%s",
                    fileName, content.length(), new Date());

        } catch (Exception e) {
            log.error("追加文件内容失败：{}", fileName, e);
            return "追加文件内容失败：" + e.getMessage();
        }
    }

    @Tool(description = "List all files in the file directory with their basic information.")
    public String listFiles() {
        log.info("Spring AI工具列出文件列表");

        try {
            File dir = new File(FILE_DIR);
            if (!dir.exists() || !dir.isDirectory()) {
                return "文件目录不存在或不是目录：" + FILE_DIR;
            }

            File[] files = dir.listFiles();
            if (files == null || files.length == 0) {
                return "文件目录为空：" + FILE_DIR;
            }

            StringBuilder sb = new StringBuilder();
            sb.append("文件列表（共 ").append(files.length).append(" 个文件）：\n\n");

            // 按文件名排序
            Arrays.sort(files, (f1, f2) -> f1.getName().compareToIgnoreCase(f2.getName()));

            for (File file : files) {
                if (file.isFile()) {
                    sb.append("📄 ").append(file.getName());
                    sb.append(" (").append(formatFileSize(file.length())).append(")");
                    sb.append(" - 修改时间：").append(new Date(file.lastModified()));
                    sb.append("\n");
                }
            }

            return sb.toString();

        } catch (Exception e) {
            log.error("列出文件失败", e);
            return "列出文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "Delete a file from the file directory.")
    public String deleteFile(@ToolParam(description = "Name of the file to delete") String fileName) {
        log.info("Spring AI工具删除文件：{}", fileName);

        try {
            if (!isValidFileName(fileName)) {
                return "错误：文件名包含非法字符或路径";
            }

            String filePath = FILE_DIR + "/" + fileName;
            File file = new File(filePath);

            if (!file.exists()) {
                return "错误：文件不存在 - " + fileName;
            }

            if (!file.isFile()) {
                return "错误：指定路径不是文件 - " + fileName;
            }

            boolean deleted = file.delete();
            if (deleted) {
                return String.format("文件删除成功：%s\n删除时间：%s", fileName, new Date());
            } else {
                return "文件删除失败：" + fileName;
            }

        } catch (Exception e) {
            log.error("删除文件失败：{}", fileName, e);
            return "删除文件失败：" + e.getMessage();
        }
    }

    @Tool(description = "Check if a file exists and get its basic information.")
    public String getFileInfo(@ToolParam(description = "Name of the file to check") String fileName) {
        log.info("Spring AI工具获取文件信息：{}", fileName);

        try {
            if (!isValidFileName(fileName)) {
                return "错误：文件名包含非法字符或路径";
            }

            String filePath = FILE_DIR + "/" + fileName;
            File file = new File(filePath);

            if (!file.exists()) {
                return "文件不存在：" + fileName;
            }

            StringBuilder sb = new StringBuilder();
            sb.append("文件信息：").append(fileName).append("\n");
            sb.append("文件路径：").append(filePath).append("\n");
            sb.append("文件大小：").append(formatFileSize(file.length())).append("\n");
            sb.append("创建时间：").append(new Date(file.lastModified())).append("\n");
            sb.append("是否可读：").append(file.canRead() ? "是" : "否").append("\n");
            sb.append("是否可写：").append(file.canWrite() ? "是" : "否").append("\n");
            sb.append("文件类型：").append(getFileExtension(fileName).toUpperCase()).append("\n");

            return sb.toString();

        } catch (Exception e) {
            log.error("获取文件信息失败：{}", fileName, e);
            return "获取文件信息失败：" + e.getMessage();
        }
    }

    @Tool(description = "Search for files by name pattern in the file directory.")
    public String searchFiles(@ToolParam(description = "Search pattern (supports wildcards like *.txt)") String pattern) {
        log.info("Spring AI工具搜索文件：{}", pattern);

        try {
            File dir = new File(FILE_DIR);
            if (!dir.exists() || !dir.isDirectory()) {
                return "文件目录不存在：" + FILE_DIR;
            }

            File[] files = dir.listFiles();
            if (files == null || files.length == 0) {
                return "文件目录为空";
            }

            // 将通配符模式转换为正则表达式
            String regex = pattern.replace("*", ".*").replace("?", ".");

            List<File> matchedFiles = Arrays.stream(files)
                    .filter(File::isFile)
                    .filter(f -> f.getName().matches(regex))
                    .collect(Collectors.toList());

            if (matchedFiles.isEmpty()) {
                return "未找到匹配的文件：" + pattern;
            }

            StringBuilder sb = new StringBuilder();
            sb.append("搜索结果（共 ").append(matchedFiles.size()).append(" 个文件匹配 \"").append(pattern).append("\"）：\n\n");

            for (File file : matchedFiles) {
                sb.append("📄 ").append(file.getName());
                sb.append(" (").append(formatFileSize(file.length())).append(")");
                sb.append(" - ").append(new Date(file.lastModified()));
                sb.append("\n");
            }

            return sb.toString();

        } catch (Exception e) {
            log.error("搜索文件失败：{}", pattern, e);
            return "搜索文件失败：" + e.getMessage();
        }
    }

    /**
     * 验证文件名是否安全
     */
    private boolean isValidFileName(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return false;
        }

        // 禁止路径遍历和特殊字符
        return !fileName.contains("..") &&
                !fileName.contains("/") &&
                !fileName.contains("\\") &&
                !fileName.contains(":") &&
                fileName.length() <= 255;
    }

    /**
     * 检查文件类型是否被允许
     */
    private boolean isAllowedFileType(String fileName) {
        String extension = getFileExtension(fileName);
        return ALLOWED_EXTENSIONS.contains(extension.toLowerCase());
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        int lastDot = fileName.lastIndexOf('.');
        if (lastDot == -1 || lastDot == fileName.length() - 1) {
            return "";
        }
        return fileName.substring(lastDot + 1);
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.1f KB", size / 1024.0);
        } else {
            return String.format("%.1f MB", size / (1024.0 * 1024.0));
        }
    }
}